#include "rtp/Packet.h"
#include <cstdint>
#include <string>
#include <arpa/inet.h>

#include "rtp/SenderReport.h"
#include "rtp/ReceiverReport.h"
#include "rtp/Sdes.h"
#include "rtp/Feedback.h"

namespace Rtp {
    namespace Rtcp {
        uint8_t Buffer[BufferSize];

        std::map<Rtp::Rtcp::Type, std::string> Rtp::Rtcp::Packet::type2String {
            { Type::SR, "SR" },
            { Type::RR, "RR" },
            { Type::SDES, "SDES" },
            { Type::BYE, "BYE" },
            { Type::APP, "APP" },
            { Type::RTPFB, "RTPFB" },
            { Type::PSFB, "PSFB" },
            { Type::XR, "XR" }
        };

        Packet* Packet::Parse(const uint8_t *data, size_t len) {
            Packet *first { nullptr };
            Packet *current { nullptr };
            Packet *last { nullptr };

            while (len > 0u) {
                if (!Packet::IsRtcp(data, len)) {
                    return first;
                }

                auto *header = const_cast<CommonHeader *>(reinterpret_cast<const CommonHeader*>(data));
                const size_t packetLen =  static_cast<size_t>(ntohs(header->length) + 1) * 4;

                if (len < packetLen) {
                    return first;
                }

                switch (Type(header->packetType)) {
                case Type::SR:{
                    current = SenderReportPacket::Parse(data, packetLen);
                    if (!current) {
                        break;
                    }
                    if (header->count > 0) {
                        Packet *rr = ReceiverReportPacket::Parse(data, packetLen, current->GetSize());
                        if (!rr) {
                            break;
                        }
                        current->SetNext(rr);
                    }
                    break;
                }
                case Type::RR:{
                    current = ReceiverReportPacket::Parse(data, packetLen);
                    break;
                }
                case Type::SDES: {
                    current = SdesPacket::Parse(data, packetLen);
                    break;
                }
                case Type::BYE: {
                    break;
                }

                case Type::APP: {
                    break;
                }

                case Type::RTPFB: {
                    break;
                }
                case Type::PSFB: {
                    break;
                }
                case Type::XR: {
                    break;
                }
                default:
                    break;
                }

                if (!current) {
                    std::string packetType = Type2String(Type(header->packetType));
                    if (Type(header->packetType) == Type::PSFB) {
                        packetType += " " + FeedbackPsPacket::MessageType2String(static_cast<FeedbackPs::MessageType>(header->count));
                    } else if (Type(header->packetType) == Type::RTPFB) {
                        // TODO
                        packetType += ""

                    }
                    return first;
                }
                Packet *packet { nullptr };
                switch (static_cast<Type>(header->packetType)) {
                    case Type::SR:
                        packet = new Rtcp::SenderReport(header);
                        break;
                    case Type::RR:
                        packet = new Rtcp::ReceiverReport(header);
                        break;
                    case Type::SDES:
                        packet = new Rtcp::SourceDescription(header);
                        break;
                    case Type::BYE:
                        packet = new Rtcp::Goodbye(header);
                        break;
                    case Type::APP:
                        packet = new Rtcp::ApplicationDefined(header);
                        break;
                    case Type::RTPFB:
                        packet = new Rtcp::TransportFeedback(header);
                        break;
                    case Type::PSFB:
                        packet = new Rtcp::PayloadFeedback(header);
                        break;
                    case Type::XR:
                        packet = new Rtcp::ExtendedReport(header);
                        break;
                    default:
                        packet = nullptr;
                }

                if (!packet) {
                    break;
                }

                if (!first) {
                    first = packet;
                    current = first;
                } else {
                    current->SetNext(packet);
                    current = packet;
                }

                last = packet;

                data += packetLen;
                len -= packetLen;
            }
        }
    }

    



}